package github.sf.mod.calculate;

import java.util.ArrayList;
import java.util.List;

/**
 * 用于扫描表达式生成token
 *
 * @author zhoup
 */
public class Scanner {
    private List<Token> tokens = new ArrayList<>();
    private CharStream charStream;

    public Scanner(CharStream charStream) {
        this.charStream = charStream;
    }

    public Token next() {
        if (!tokens.isEmpty()) {
            return tokens.remove(0);
        }
        return getAToken();
    }

    public Token peek() {
        if (!tokens.isEmpty()) {
            return tokens.get(0);
        }
        Token t = getAToken();
        this.tokens.add(t);
        return t;
    }

    public Token peek2() {
        if (tokens.size() > 1) {
            return tokens.get(1);
        }
        Token t = null;
        while (t == null) {
            this.tokens.add(this.getAToken());
            if (tokens.size() > 1) {
                t = this.tokens.get(1);
            }
        }
        return t;
    }

    /**
     * calculate=expression operation expression|expression
     * expression=unary (operation unary)*|(expression)
     * unary=+|- number
     * operation=+|-|*|/
     */
    private Token getAToken() {
        skipWhiteSpaces();
        if (charStream.eof()) {
            return new Token(TokenType.Eof, "EOF", charStream.getCol());
        } else {
            char ch = charStream.peek();
            if (ch == '(') {
                charStream.next();
                return new Token(TokenType.OpenParen, "(", charStream.getCol());
            } else if (ch == ')') {
                charStream.next();
                return new Token(TokenType.CloseParen, ")", charStream.getCol());
            } else if (isDigit(ch)) {
                charStream.next();
                char ch1 = charStream.peek();
                StringBuilder literal = new StringBuilder();
                if (ch == '0') {
                    //暂不支持其它进制，支持十进制
                    if (!(ch1 >= '1' && ch1 <= '9')) {
                        literal = new StringBuilder("0");
                    } else {
                        System.err.println("0 cannot be followed by other digit now ,at col :" + charStream.getCol());
                        //暂时先跳过去
                        charStream.next();
                        return this.getAToken();
                    }
                } else if (ch >= '1' && ch <= '9') {
                    literal.append(ch);
                    while (this.isDigit(ch1)) {
                        ch = charStream.next();
                        literal.append(ch);
                        ch1 = charStream.peek();
                    }
                }
                //加上小数点
                if (ch1 == '.') {
                    //小数字面量
                    literal.append(".");
                    charStream.next();
                    ch1 = charStream.peek();
                    while (this.isDigit(ch1)) {
                        ch = charStream.next();
                        literal.append(ch);
                        ch1 = charStream.peek();
                    }
                    return new Token(TokenType.DecimalLiteral, literal.toString(), charStream.getCol());
                } else {
                    return new Token(TokenType.IntegerLiteral, literal.toString(), charStream.getCol());
                }
            } else if (ch == '.') {
                StringBuilder literal = new StringBuilder("0");
                //小数字面量
                literal.append(".");
                charStream.next();
                char ch1 = charStream.peek();
                while (this.isDigit(ch1)) {
                    ch = charStream.next();
                    literal.append(ch);
                    ch1 = charStream.peek();
                }
                return new Token(TokenType.DecimalLiteral, literal.toString(), charStream.getCol());
            } else if (ch == '+') {
                charStream.next();
                return new Token(TokenType.Operation, "+", charStream.getCol(), Op.Plus);
            } else if (ch == '-') {
                charStream.next();
                return new Token(TokenType.Operation, "-", charStream.getCol(), Op.Minus);
            } else if (ch == '*') {
                charStream.next();
                return new Token(TokenType.Operation, "*", charStream.getCol(), Op.Multiply);
            } else if (ch == '/') {
                charStream.next();
                return new Token(TokenType.Operation, "/", charStream.getCol(), Op.Divide);
            } else {
                System.out.println("Unrecognized pattern meeting :" + ch + "at col: " + charStream.getCol());
                return null;
            }
        }
    }

    private Token parserExpression() {
        charStream.next();
        char ch = charStream.peek();
        if (ch == '+') {

        } else if (ch == '-') {

        } else if (isDigit(ch)) {

        }
        return null;
    }

    private boolean isDigit(char ch) {
        return (ch >= '0' && ch <= '9');
    }

    private boolean isWhiteSpace(char ch) {
        return (ch == ' ' || ch == '\n' || ch == '\t');
    }

    /**
     * 跳过空白字符
     */
    private void skipWhiteSpaces() {
        while (isWhiteSpace(charStream.peek())) {
            charStream.next();
        }
    }
}

//                Token token = parserExpression();
//                char ch1 = charStream.peek();
//                if (ch1 == ')') {
//                    return token;
//                } else {
//                    System.err.println("We Excepted ')' but  got '" + ch1 + "' in col:" + charStream.getCol());
//                }
//            } else {
//解析表达式为token
//                return parserExpression();

//            }
